//
//  HelloWorldLayer.mm
//  projekt1
//
//  Created by A B on 1/10/12.
//  Copyright __MyCompanyName__ 2012. All rights reserved.
//

// Import the interfaces
#import "HelloWorldLayer.h"
#import "MyContactListener.h"
#import "ContactTypes.h"
#import "NextLevelScene.h"
#import "MainMenuScene.h"
#define PTM_RATIO 32.0

#define PLAYER_SPRITE_PATH @"ball1.png"
#define ENEMY_SPRITE_PATH @"monster.png"
#define BACKGROUND_PATH @"background1.jpg"
#define TILE_MAP_PATH @"lvl_1.tmx"

#define COLISION_LAYER_NAME @"Tiles"
#define DECORATION_LAYER_NAME @"Grass"
#define DECORATION_LAYER_NAME2 @"Grass2"
#define SPAWN_LAYER_NAME @"Spawn"

#define BACKGROUND_MUSIC_PATH @"GameForest.mp3"
#define ENEMY_CONTACT_SOUND @"enemy_hit.mp3"

#define GROUND_TILE 51
#define PLAYER_SPAWN_TILE 691
#define ENEMY_SPAWN_TILE 735
#define ENEMY_BLOCKER_TILE 744
#define FINISH_TILE 139
#define SOUND_ENABLES false


// HelloWorldLayer implementation
@implementation HelloWorldLayer

int numFootContacts;
BOOL GAME_DEBUG = false;
BOOL* enemyDirection;
int moves;
float enemyScale = 1.5f;
int curLevel;
int score;
+(CCScene *) sceneWith:(int) level
{
	// 'scene' is an autorelease object.
	CCScene *scene = [CCScene node];
	
	// 'layer' is an autorelease object.
	HelloWorldLayer *layer = [[HelloWorldLayer alloc] initWith:level];
	
	// add layer as a child to scene
	[scene addChild: layer];
	
	// return the scene
	return scene;
}


-(void) enemyContact{
    if(SOUND_ENABLES){
        [[SimpleAudioEngine sharedEngine] playEffect:ENEMY_CONTACT_SOUND];
    }
    
    score--;

}

-(void) groundContact{
    if(SOUND_ENABLES){
        [[SimpleAudioEngine sharedEngine] playEffect:ENEMY_CONTACT_SOUND];
    }
}

-(void) setupPlayer {
    //setup player sprite
    ball = [CCSprite spriteWithFile: PLAYER_SPRITE_PATH];
    ball.anchorPoint = ccp(0.5f, 0.5f);
    ball.scaleX = 0.5f;
    ball.scaleY = 0.5f;
    ballWidth = 32;
    ballHeight = 32;
    
    
    //setup player physics
    
    // Create ball body and shape
    b2BodyDef ballBodyDef;
    ballBodyDef.type = b2_dynamicBody;
    ballBodyDef.position.Set(initialX+0.5f, initialY+0.5f);
    ballBodyDef.userData = ball;
    ballBodyDef.fixedRotation = false;
    body = world->CreateBody(&ballBodyDef);
    
    b2CircleShape circle;
    circle.m_radius = (float)ballWidth / (PTM_RATIO*2);
    b2FixtureDef ballShapeDef;
    ballShapeDef.shape = &circle;
    ballShapeDef.density = 2.0f;
    ballShapeDef.friction = 0.2f;
    ballShapeDef.restitution = 0.6f;
    body->CreateFixture(&ballShapeDef);
    
    
    //add foot sensor
    b2BodyDef footBodyDef;
    footBodyDef.type = b2_dynamicBody;
    b2CircleShape footShape;
    footShape.m_radius=circle.m_radius+0.25f;
    b2FixtureDef footFixtureDef;
    footFixtureDef.shape = &footShape;
    footFixtureDef.density = 0;
    footFixtureDef.isSensor=true;
    b2Fixture* footSensorFixture = body->CreateFixture(&footFixtureDef);
    footSensorFixture->SetUserData((void*)PLATFORM_CONTACT);
}

-(void) setupHUD{
    //setup a label display of score
    scoreLabel = [CCLabelTTF labelWithString:[NSString stringWithFormat:@"score: %d", flowerCount] fontName:@"Times New Roman" fontSize:32];
    scoreLabel.position = ccp(winSize.width - scoreLabel.contentSize.width, winSize.height - scoreLabel.contentSize.height/2);
}

-(void) setupBackground{
    //background image
    background =[CCSprite spriteWithFile: BACKGROUND_PATH];
    background.scale = 1.0f;
    background.anchorPoint = ccp(0,0);
}

-(void) setupMap:(int) level{
    //Setup Map 
    NSString *mapPath = [[NSString alloc] initWithFormat:@"lvl_%d.tmx", level];
    score = 100*level;
    
    collisionMap = [CCTMXTiledMap tiledMapWithTMXFile: mapPath];
    collisionMap.anchorPoint = ccp(0,0);
    
    //Set up all the map layers
    colLayer = [collisionMap layerNamed: COLISION_LAYER_NAME];
    flowerLayer = [collisionMap layerNamed: DECORATION_LAYER_NAME];
    spawnLayer = [collisionMap layerNamed: SPAWN_LAYER_NAME];
    
}

-(void) setupWorld{
    // Create a world
    b2Vec2 gravity = b2Vec2(0.0f, -10.0f);
    bool doSleep = true;
    world = new b2World(gravity, doSleep);
}

-(void) setupContactListener{
    //setup contact listener
    footContactListener = new MyContactListener(self);
    world->SetContactListener(footContactListener);
}

-(void) setupPlatforms{
    //create boxes for each tile
    int rowCount = collisionMap.mapSize.height;
    int colCount = collisionMap.mapSize.width;
    
    for(int row=0;row<rowCount;row++){
        for(int col=0;col<colCount;col++){
            
            int idd = [colLayer tileGIDAt:ccp(col, row)];
            int idd2 = [spawnLayer tileGIDAt:ccp(col, row)];
            
            if(idd == GROUND_TILE) {
                
                b2BodyDef tileBodyDef;
                tileBodyDef.type = b2_staticBody;
                tileBodyDef.position.Set(col, rowCount-row);
                b2Body* tile= world->CreateBody(&tileBodyDef);
                
                b2PolygonShape squere;
                squere.SetAsBox(0.5f, 0.5f, b2Vec2(0.5f, -0.5f), 0);
                
                b2FixtureDef tileShapeDef;
                tileShapeDef.shape = &squere;
                tile->CreateFixture(&tileShapeDef); 
            
            }else if(idd == FINISH_TILE){
                //add finish sensor
                b2BodyDef finishBodyDef;
                finishBodyDef.type = b2_staticBody;
                finishBodyDef.position.Set(col, rowCount-row);
                b2PolygonShape finishShape;
                finishShape.SetAsBox(0.5f, 0.5f, b2Vec2(0.5f, -0.5f), 0);

                b2FixtureDef finishFixtureDef;
                finishFixtureDef.shape = &finishShape;
                finishFixtureDef.density = 0;
                finishFixtureDef.isSensor=true;
                
                b2Body* finish = world->CreateBody(&finishBodyDef);
                
                b2Fixture* finishSensorFixture = finish->CreateFixture(&finishFixtureDef);
                finishSensorFixture->SetUserData((void*)FINISH_CONTACT);
            
            }
            
            
            if(idd2 == PLAYER_SPAWN_TILE){
                [[spawnLayer tileAt:ccp(col, row)] setOpacity:0]; 
                
                //spawn point
                initialX = col;
                initialY = rowCount-row;
            }
            
            
            else if(idd2 == ENEMY_SPAWN_TILE){
                [[spawnLayer tileAt:ccp(col, row)] setOpacity:0]; 
                
                CCSpriteBatchNode *spriteSheet =[CCSpriteBatchNode batchNodeWithFile: ENEMY_SPRITE_PATH capacity:4];
                [self addChild:spriteSheet];
                
                for(int i=0;i<4;i++){
                    CCSpriteFrame* frame =[[CCSpriteFrame alloc]
                                           initWithTexture:spriteSheet.texture rect:
                                           CGRectMake(i*62, 56, 62, 56)];
                    [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFrame:frame name:[NSString stringWithFormat:@"enemyFrame%d",i]];                      
                    [frame release];                      
                }
                
                CCSprite* enemySprite =[[CCSprite alloc] initWithSpriteFrameName:[NSString stringWithFormat:@"enemyFrame%d",0]];
                [spriteSheet addChild:enemySprite];
                
                NSMutableArray* animFrames = [NSMutableArray array];
                for(int i=0;i<4;i++){
                    CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache]
                                            spriteFrameByName:[NSString stringWithFormat:@"enemyFrame%d",i]];
                    [animFrames addObject:frame];
                }
                CCAnimation *animation =[CCAnimation animationWithFrames:animFrames delay:0.2f];
                [enemySprite runAction:[CCRepeatForever actionWithAction:
                                   [CCAnimate actionWithAnimation:animation restoreOriginalFrame:NO]]];
            
                enemySprite.scaleX = enemyScale;
                enemySprite.scaleY = enemyScale;
                enemySprite.anchorPoint = ccp(0.5f, 0.55f);

                                
                
                //setup enemy physics
                
                // Create enemy body and shape
                b2BodyDef enemyBodyDef;
                enemyBodyDef.type = b2_dynamicBody;
                enemyBodyDef.position.Set(col+0.5f, rowCount-row+0.5f);
                enemyBodyDef.userData = enemySprite;
                enemyBodyDef.fixedRotation = false;
                b2Body* enemy = world->CreateBody(&enemyBodyDef);
                
                b2CircleShape circle;
                circle.m_radius = 0.9f;
                b2FixtureDef enemyShapeDef;
                enemyShapeDef.shape = &circle;
                enemyShapeDef.density = 2000.0f;
                enemyShapeDef.friction = 10.0f;
                enemyShapeDef.restitution = 0.0f;
                enemy->CreateFixture(&enemyShapeDef);
                
                b2FixtureDef enemySensorFixtureDef;
                enemySensorFixtureDef.shape = &circle;
                enemySensorFixtureDef.isSensor=true;
                b2Fixture* enemySensorFixture = enemy->CreateFixture(&enemySensorFixtureDef);
                enemySensorFixture->SetUserData((void*) (enemyCount+7));

                enemys[enemyCount] = enemy;
                ++enemyCount;

                                
            }else if(idd2 == ENEMY_BLOCKER_TILE){
                [[spawnLayer tileAt:ccp(col, row)] setOpacity:0]; 
                
                //enemy blocker
                //add enemy blocker sensor
                b2BodyDef blockerBodyDef;
                blockerBodyDef.type = b2_staticBody;
                blockerBodyDef.position.Set(col, rowCount-row);
                b2PolygonShape blockerShape;
                blockerShape.SetAsBox(0.5f, 0.5f, b2Vec2(0.5f, -0.5f), 0);
                
                b2FixtureDef blockerFixtureDef;
                blockerFixtureDef.shape = &blockerShape;
                blockerFixtureDef.density = 0;
                blockerFixtureDef.isSensor=true;
                
                b2Body* blocker = world->CreateBody(&blockerBodyDef);
                
                b2Fixture* blockerSensorFixture = blocker->CreateFixture(&blockerFixtureDef);
                blockerSensorFixture->SetUserData((void*)BLOCKER_CONTACT);
                
            } 
            
        }
    }
}


// on "init" you need to initialize your instance
-(id) initWith:(int)level
{
	// always call "super" init
	// Apple recommends to re-assign "self" with the "super" return value
	if( (self=[super init])) {

        numFootContacts = 0;
        moves = 0;
        curLevel = level;
        enemyDirection = new BOOL[100];
        
        for(int i=0; i<100; i++){
            enemys[i] = NULL;
            enemyDirection[i]=false;
        }
        
		//for debug
        debugDraw = new GLESDebugDraw(PTM_RATIO);

        self.isTouchEnabled = YES;
        
        //ask director for window size
        winSize = [[CCDirector sharedDirector] winSize];
        
        
        [self setupBackground];        
        [self setupMap:level];     
        [self setupWorld];
        [self setupPlatforms];
        [self setupPlayer];
        [self setupHUD];
        
        //add everything to self
        
        //void node, parent node
        CCParallaxNode *voidNode = [CCParallaxNode node];
        [voidNode addChild:background z:-1 parallaxRatio:ccp(0.1f, 0.05f) positionOffset:ccp(-100,-100)];
        
        [voidNode addChild:collisionMap z:1 parallaxRatio:ccp(1.0f,1.0f) positionOffset:ccp(0,0)];
        
        
        [self addChild:scoreLabel z:10];
        [self addChild:voidNode z:-1 tag:1];
        [self addChild:ball z:2];
        
        [self setupContactListener];       
        
        CCMenuItem *pause = [CCMenuItemFont itemFromString:@"Pause" target:self selector:@selector(pauseGame)];
        menu = [CCMenu menuWithItems:pause, nil];
        [self addChild:menu z:12];
       
         
        //for debug
        if(GAME_DEBUG){
            world->SetDebugDraw(debugDraw);
            uint32 flags=0;
            flags += b2DebugDraw::e_shapeBit;
            debugDraw->SetFlags(flags);
        }
        
        if(SOUND_ENABLES){
            [[SimpleAudioEngine sharedEngine] playBackgroundMusic: BACKGROUND_MUSIC_PATH];
        }

        [self schedule:@selector(tick:) ];
        
    }
	return self;
}

-(void) pauseGame{
    [[CCDirector sharedDirector] pushScene: [MainMenuScene sceneWith:YES]];
}

-(void) resumeGame{
    [self resumeSchedulerAndActions];
}

-(void) registerWithTouchDispatcher
{
    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
bool draging;

-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    draging = true;
    endTouchHere = [touch locationInView: [touch view]];
    return YES;
}



-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event 
{  
    endTouchHere = [touch locationInView: [touch view]];
}


-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event{
    draging = false;
    endTouchHere = [touch locationInView: [touch view]];
    	
    if(numFootContacts < 1){
        return;
    }
    b2Vec2 force = b2Vec2((endTouchHere.x - 240)/8, (-endTouchHere.y + 200)/8);
    body->ApplyLinearImpulse(force, body->GetWorldCenter());
    moves++;
}


-(void) draw
{
    
    if(GAME_DEBUG){
        glDisable(GL_TEXTURE_2D);
        glDisableClientState(GL_COLOR_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    
        world->DrawDebugData();
    
        glEnable(GL_TEXTURE_2D);
        glEnableClientState(GL_COLOR_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    
    }

    
    if(draging) {
        
        CGPoint start = ccp(body->GetPosition().x * PTM_RATIO, body->GetPosition().y * PTM_RATIO);
        CGPoint end = ccp(endTouchHere.x - 240 + start.x, -endTouchHere.y + 200 + start.y );
        
        ccDrawLine(start, end);
    }
    
}

-(void)endLvl{
    //TODO: endLvl
    [[CCDirector sharedDirector] replaceScene: [NextLevelScene sceneWith:score:moves:curLevel]];    
}

- (void)tick:(ccTime) dt {
    //update world
    world->Step(dt, 10, 10);
    
    //update ball sprite using data from world
    CCSprite* ballData = (CCSprite *)body->GetUserData();
    ballData.position = ccp(body->GetPosition().x * PTM_RATIO,
                            body->GetPosition().y * PTM_RATIO);
    ballData.rotation = -CC_RADIANS_TO_DEGREES(body->GetAngle());
    
    
    int index = 0;
    while(enemys[index] != NULL) {
        
        b2Vec2 force = enemyDirection[index]? b2Vec2(3, 0): b2Vec2(-3,0);
        enemys[index]->SetLinearVelocity(force);
        
        CCSprite* enemyData = (CCSprite *)enemys[index]->GetUserData();
        int newX = enemys[index]->GetPosition().x * PTM_RATIO;
        int newY = enemys[index]->GetPosition().y * PTM_RATIO;

 	enemyData.scaleX = enemyDirection[index]? -enemyScale: enemyScale;        
       
        enemyData.position = ccp(newX, newY);
        index++;
    }

    //move camera
    CGPoint newPos = ccp(-ballData.position.x + 240 , -ballData.position.y + 120);
    [self setPosition:newPos];
    
    
    //move score label and update score
    [scoreLabel setString:[NSString stringWithFormat:@"score: %d", score]];
     scoreLabel.position = ccp(
                               winSize.width - scoreLabel.contentSize.width + ballData.position.x - 240 ,
                               winSize.height - scoreLabel.contentSize.height/2 + ballData.position.y - 120);
    
    menu.position = ccp(
                         winSize.width - scoreLabel.contentSize.width + ballData.position.x - 240 ,
                         ballData.position.y - 120 + scoreLabel.contentSize.height/2
                         );

    
}


// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
	// in case you have something to dealloc, do it in this method
	// in this particular example nothing needs to be released.
	// cocos2d will automatically release all the children (Label)
	
	// don't forget to call "super dealloc"
    
    delete world;
    delete debugDraw;
    delete footContactListener;
    
    body = NULL;
    world = NULL;
    footContactListener = NULL;
    
	[super dealloc];
}
@end
